/**
 * 
 */
package org.metaverse.restful;

import static org.metaverse.restful.ConstraintJSONFormat.fromJSON;
import static org.metaverse.restful.ConstraintJSONFormat.toJSON;
import static org.metaverse.restful.RDFFormatHelper.toRDFFormat;

import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.util.List;
import java.util.concurrent.Callable;

import org.json.JSONException;
import org.metaverse.warehouse.Fetcher;
import org.metaverse.warehouse.Senary;
import org.metaverse.warehouse.Uploader;
import org.metaverse.warehouse.WarehouseException;
import org.metaverse.warehouse.com.Constraint;
import org.metaverse.warehouse.com.util.BasicConstraint;
import org.metaverse.warehouse.util.RDFParseUtil;
import org.openrdf.model.Statement;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFWriter;
import org.openrdf.rio.Rio;
import org.restlet.data.ClientInfo;
import org.restlet.data.MediaType;
import org.restlet.data.Preference;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;
import org.singularity.io.CloseableIterator;

/**
 * @author vjache
 *
 */
public class DatasetResource extends ServerResource {

	/**
	 * 
	 */
	public DatasetResource() {}
	
	@Override
	protected void doInit() throws ResourceException {
		System.out.println("INIT");
		super.doInit();
	}
	
	@Post
	public String upload(Representation  aText) throws Exception
	{
		Uploader uploader = Activator.getService(Uploader.class);
		if(uploader == null)
			return "Sorry, service unavailable.";
		
		final MediaType mediaType = aText.getMediaType();
		
		final RDFFormat format = toRDFFormat(mediaType);
		
		final String rdfText = aText.getText();
		final Callable<List<Statement>> call = RDFParseUtil.createCall(rdfText, format);
		final List<Statement> r = call.call();
		uploader.assertStatements(r.iterator());
		return "Ok";
	}

	
	@Get//(value="")
	public Representation fetch() throws SemanticException
	{	
		final MediaType mediaType = chooseAcceptableMediaType(getClientInfo());
		final RDFFormat format = toRDFFormat(mediaType);
		
		Fetcher fetcher = Activator.getService(Fetcher.class);
		if(fetcher == null)
		{
			throw new SemanticException(
					format, 
					SemanticException.ErrorCode.FetcherOutOfServiceError, 
					"Fetcher service unavailable.");
		}
		Constraint constraint;
		try {
			if(getQuery().isEmpty())
				constraint = new BasicConstraint();
			else
			{
				String constrJsonStr = getQuery().getFirstValue("constraint");
				if(constrJsonStr==null)
					constraint = new BasicConstraint();
				else
					constraint = fromJSON(
							constrJsonStr, 
							fetcher.getValueFactory());
			}
		} catch (JSONException e) {
			throw new SemanticException(
					format, 
					SemanticException.ErrorCode.BadConstraintError, 
					e);
		}
		
		CloseableIterator<Senary> fetched = null;
		try
		{
			fetched = fetcher.fetch(constraint);
			StringWriter r = new StringWriter();
			RDFWriter writer = Rio.createWriter(format, r);
			writer.startRDF();
			while(fetched.hasNext())
			{
				Senary sen = fetched.next();
				writer.handleStatement(sen);
			}
			writer.endRDF();
			r.close();
			return new StringRepresentation(r.toString(),mediaType);
		} catch (WarehouseException e) {
			throw new SemanticException(
					format, 
					SemanticException.ErrorCode.FetcherError, 
					e);
		} catch (RDFHandlerException e) {
			throw new SemanticException(
					format, 
					SemanticException.ErrorCode.WarehouseError, 
					e);
		} catch (IOException e) {
			throw new SemanticException(
					format, 
					SemanticException.ErrorCode.WarehouseError, 
					e);
		}
		finally
		{
			if(fetched!=null)
				try 
				{fetched.close();} 
				catch (IOException e) 
				{e.printStackTrace();}
		}
//		sb.append(this.getClientInfo().getUser()).append("\r\n");
//		sb.append(this.getRequest().getAttributes()).append("\r\n");
//		sb.append(this.getRequest().getEntityAsText()).append("\r\n");
//		sb.append(this.getQuery()).append("\r\n");
//		sb.append("A query:"+Arrays.toString(this.getQuery().getValuesArray("query"))).append("\r\n");
//		sb.append("A query1:"+this.getQuery().getFirstValue("query")).append("\r\n");
////		sb.append(uri).append("\r\n");
//		//this.getResponse().getCookieSettings().clear();
	}

	private MediaType chooseAcceptableMediaType(ClientInfo clientInfo) {
		final MediaType mediaType;
		List<Preference<MediaType>> acceptedMediaTypes = clientInfo.getAcceptedMediaTypes();
		if(acceptedMediaTypes.isEmpty())
		{
			mediaType = MediaType.APPLICATION_RDF_TRIG;
		}
		else
		{
			mediaType = acceptedMediaTypes.get(0).getMetadata();
		}
		return mediaType;
	}

	public static void main(String[] args) throws Exception {		
		ValueFactoryImpl vf = new ValueFactoryImpl();
		BasicConstraint constr = new BasicConstraint()
//			.bySubject(vf.createURI("http://localhot#rsc-1"))
			.byContext(vf.createURI("http://www.metaverse.org/users/vjache/def-context"));
//			.byLastAssertTime(new Greater(Converter.valueOf(new Date(), vf))
//			);
		String json = toJSON(constr);
		System.out.println(json);
		URI uri = new URI("http", "localhost:8182", "/warehouse/dataset", "query="+json, null);
		
		System.out.println(uri);
	}
}
